%%% @author CA Meijer
%%% @copyright 2012 CA Meijer
%%% @doc HTTP client profile ID server. HTTP client connections must be
%%%      associated with a unique profile. This gen_server can be used
%%%      to get a profile identifier.
%%% @end

-module(nimbula_httpc_profile_id_server).

-behaviour(gen_server).
%% --------------------------------------------------------------------
%% Include files
%% --------------------------------------------------------------------

%% --------------------------------------------------------------------
%% External exports
-export([start_link/1,
		 get_profile_id/0,
		 restore_profile_id/1]).

%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).

-record(state, {ets_id}).

%% API
start_link(EtsId) ->
	gen_server:start_link({local, ?MODULE}, ?MODULE, [EtsId], []).

get_profile_id() ->
	gen_server:call(?MODULE, get_profile_id).

restore_profile_id(Id) ->
	gen_server:call(?MODULE, {restore_profile_id, Id}).
	

%% Server functions
%% Function: init/1
%% Description: Initiates the server
%% Returns: {ok, State}          |
%%          {ok, State, Timeout} |
%%          ignore               |
%%          {stop, Reason}
%% --------------------------------------------------------------------
init([EtsId]) ->
    {ok, #state{ets_id=EtsId}}.

%% --------------------------------------------------------------------
%% Function: handle_call/3
%% Description: Handling call messages
%% Returns: {reply, Reply, State}          |
%%          {reply, Reply, State, Timeout} |
%%          {noreply, State}               |
%%          {noreply, State, Timeout}      |
%%          {stop, Reason, Reply, State}   | (terminate/2 is called)
%%          {stop, Reason, State}            (terminate/2 is called)
%% --------------------------------------------------------------------
handle_call(get_profile_id, _From, State) ->
	[{available_ids, AvailableIds}] = ets:lookup(State#state.ets_id, available_ids),
	case AvailableIds of
		[H|T] ->
			Id = H,
			ets:insert(State#state.ets_id, {available_ids, T});
		[] ->
			[{number_of_ids, IdOld}] = ets:lookup(State#state.ets_id, number_of_ids),
			Id = IdOld + 1,
			ets:insert(State#state.ets_id, {number_of_ids, Id})
	end,
    {reply, list_to_atom(integer_to_list(Id)), State};
handle_call({restore_profile_id, Id}, _From, State) ->
	[{available_ids, AvailableIds}] = ets:lookup(State#state.ets_id, available_ids),
	H = list_to_integer(atom_to_list(Id)),
	ets:insert(State#state.ets_id, {available_ids, [H|AvailableIds]}),
    {reply, ok, State}.

%% --------------------------------------------------------------------
%% Function: handle_cast/2
%% Description: Handling cast messages
%% Returns: {noreply, State}          |
%%          {noreply, State, Timeout} |
%%          {stop, Reason, State}            (terminate/2 is called)
%% --------------------------------------------------------------------
handle_cast(_Msg, State) ->
    {noreply, State}.

%% --------------------------------------------------------------------
%% Function: handle_info/2
%% Description: Handling all non call/cast messages
%% Returns: {noreply, State}          |
%%          {noreply, State, Timeout} |
%%          {stop, Reason, State}            (terminate/2 is called)
%% --------------------------------------------------------------------
handle_info(_Info, State) ->
    {noreply, State}.

%% --------------------------------------------------------------------
%% Function: terminate/2
%% Description: Shutdown the server
%% Returns: any (ignored by gen_server)
%% --------------------------------------------------------------------
terminate(_Reason, _State) ->
    ok.

%% --------------------------------------------------------------------
%% Func: code_change/3
%% Purpose: Convert process state when code is changed
%% Returns: {ok, NewState}
%% --------------------------------------------------------------------
code_change(_OldVsn, State, _Extra) ->
    {ok, State}.

%% --------------------------------------------------------------------
%%% Internal functions
%% --------------------------------------------------------------------

